from Sodev.Block import Block

class AsignacionContinua:
    
    def __init__(self, mem, compacter, pedido):
        self.freeBlocks = []
        self.usedBlocks = []
        self.memoriaFisica = mem
        self.setBlocks()
        self.compacter = compacter
        compacter.memoria = self
        self.mmu = pedido
        self.mmu.memoria = self
        
        
    def setBlocks(self):
        block = Block()
        block.setInitPos(0)
        block.setEndPos(self.memoriaFisica.getSize())
        self.freeBlocks.append(block)
        
    def write(self, progData,pid):
        if(self.hasSpace(self.analizeSizeOf(progData))):
            self.writeProgram(progData,pid)
        '''no hay?'''
            
    def hasSpace(self,size):
        ret = False
        n = 0
        for i in self.freeBlocks:
            n = n + i.size()
            if(i.size() >= size):
                ret = True
        
        return ret or (n>=size)
    
    def writeProgram(self,progData,pid):
        '''prog no teine size'''
        bloqueEnLista = self.takeFreeBlock(self.analizeSizeOf(progData))
        bloqueEnLista.setPid(pid)
        index = bloqueEnLista.getInitPos()
        for b in progData:
            self.writeBloques(b, index)
            index = index + b.size() 
            
        #self.usedBlocks.append(bloqueEnLista)
            
    def writeBloques(self, bloqueP, indexEnMemoria):
        i = indexEnMemoria
        for inst in bloqueP.getInstrs():
            self.memoriaFisica.write(i, inst)
            i = i+1
        
    ''' -_-'''    
    def takeFreeBlock(self, n):
        block = self.mmu.getBloqueN(n)
        if(block == None):
            self.compacter.compactar()
            return self.takeFreeBlock(n)
        else:
            '''metodo lendo despues'''
            return self.fragmentarBloques(block, n)
            '''bloqe fruta '''
        
    def fragmentarBloques(self, block, size):
            self.freeBlocks.remove(block)
            if(block.getInitPos() + size <= block.getEndPos()):
                newBlock = Block()
                newBlock.setInitPos(block.getInitPos() + size )
                newBlock.setEndPos(block.getEndPos())
                self.freeBlocks.append(newBlock)
            blockUsed = Block()
            blockUsed.setInitPos(block.getInitPos())
            blockUsed.setEndPos(block.getInitPos() + size -1)
            self.usedBlocks.append(blockUsed)
            return blockUsed 
            '''al principio deberia ir'''
     
    '''Retorna "None" si se paso de index, o no encontro un bloque con el PID solicitado'''
    def read(self,pc,pid):
        blocktmp = None
        for b in self.usedBlocks:
            if (b.getPid() == pid):
                blocktmp = b
        if(blocktmp != None):
            return self.checkMarginsOfInstruction(blocktmp,pc)
        else:
            return blocktmp
    
    '''Analiza si se paso o no de margenes, en caso de encontrar un bloque pero el PC esta fuera de margen'''    
    def checkMarginsOfInstruction(self, block, pc):
        blocktmp = block
        ret = None
        if (pc + blocktmp.getInitPos() <= blocktmp.getEndPos()):
            ret = self.memoriaFisica.read(blocktmp.getInitPos() + pc)
        
        return ret
    
    def analizeSizeOf(self,progData):
        ret = 0
        for b in progData:
            ret = ret + b.size()
        return ret
    
    def getMemoriaFisica(self):
        return self.memoriaFisica
    
    def liberarMemoria(self, pcb):
        b = None
        for bU in self.usedBlocks:
            if(pcb.getPid() == pcb.getPid()):
                b = bU
        if(b != None):
            for i in range(b.getEndPos() - b.getInitPos() + 1):
                self.memoriaFisica.write(b.getInitPos()+i, None)
            self.freeBlocks.append(b)
            self.usedBlocks.remove(b)
        return b